package org.incubator.numeric;

import java.util.Arrays;
import java.util.Collection;

import org.incubator.Generator;
import org.incubator.RandomElementGenerator;

/**
 * Selects a random integer from a collection of possibilities.
 * This generator allows allot of configuration, but at the cost
 * of performance and memory. Be careful when using this generator
 * on a large set of possibilities, as each possible value is kept
 * in memory.
 * 
 * @author Jeroen van Schagen
 * @since 1-5-2011
 */
public class RandomIntegerGenerator implements Generator<Integer> {
    private final RandomElementGenerator<Integer> delegate = new RandomElementGenerator<Integer>();

    /**
     * {@inheritDoc}
     */
    @Override
    public Integer generate() {
        return delegate.generate();
    }

    /**
     * Include a specific value to our possible values.
     * @param value the value to be included
     * @return this generator, with the included value
     */
    public RandomIntegerGenerator include(int value) {
        delegate.include(value);
        return this;
    }

    /**
     * Include a collection of values to our possible values.
     * @param values the values to be included
     * @return this generator, with the included values
     */
    public RandomIntegerGenerator includeValues(Collection<Integer> values) {
        delegate.includeElements(values);
        return this;
    }

    /**
     * Include an array of value to our possible values.
     * @param values the values to be included
     * @return this generator, with the included values
     */
    public RandomIntegerGenerator includeValues(Integer... values) {
        return this.includeValues(Arrays.asList(values));
    }

    /**
     * Include a range of values to our possible values.
     * @param range the range of values
     * @return this generator, with the included range of values
     */
    public RandomIntegerGenerator includeRange(IntegerRange range) {
        return this.includeValues(range.values());
    }

    /**
     * Include a range of values to our possible values.
     * @param min start of the value range
     * @param max end of the value range
     * @return this generator, with the include range of values
     */
    public RandomIntegerGenerator includeRange(int min, int max) {
        return this.includeRange(new IntegerRange(min, max));
    }

    /**
     * Exclude a specific element from our possible values.
     * @param value the element to be excluded
     * @return this generator, without the excluded element
     */
    public RandomIntegerGenerator exclude(int value) {
        delegate.exclude(value);
        return this;
    }

    /**
     * Exclude a collection of values from our possible values.
     * @param values the values to be excluded
     * @return this generator, without the excluded values
     */
    public RandomIntegerGenerator excludeValues(Collection<Integer> values) {
        delegate.excludeElements(values);
        return this;
    }

    /**
     * Exclude an array of values from our possible values.
     * @param values the values to be excluded
     * @return this generator, without the excluded values
     */
    public RandomIntegerGenerator excludeValues(Integer... values) {
        return this.excludeValues(Arrays.asList(values));
    }

    /**
     * Exclude a range of values from our possible values.
     * @param range the range of values
     * @return this generator, without the excluded range of values
     */
    public RandomIntegerGenerator excludeRange(IntegerRange range) {
        return this.excludeValues(range.values());
    }

    /**
     * Exclude a range of values from our possible values.
     * @param min start of the value range
     * @param max end of the value range
     * @return this generator, without the excluded range of values
     */
    public RandomIntegerGenerator excludeRange(int min, int max) {
        return this.excludeRange(new IntegerRange(min, max));
    }
}
